package nina.yiyou.salary.process.salary


import nina.yiyou.salary.process.global.GlobalResultMaker

import java.time.LocalDate
import java.time.LocalDateTime
import java.util.stream.Collectors

/**
 * 需要程序额外做逻辑生成的数据
 */
class SalaryProcessMapMaker {

  SalaryProcessMapMaker(Map globalMap, GlobalResultMaker.Result globalResult, Map basicMap, Map etcMap, Map payMap, Map attendMap, Map insuranceMap, Map fundMap) {
    _globalMap = globalMap
    _globalResult = globalResult
    _basicMap = basicMap
    _etcMap = etcMap
    _payMap = payMap
    _attendMap = attendMap
    _insuranceMap = insuranceMap
    _fundMap = fundMap
  }

  Map make() {
    return new ComputeMapMaker([
        [expandEtcMap(), this.&processEtc],
        [_attendMap, this.&processAttendance],
        [_insuranceMap, this.&processInsurance],
        [_fundMap, this.&processFund],
    ]).make()
  }

  /**
   * 不强制<工资其他表>写全部人，没写的用<考勤表>补全
   * 补全<工资其他表>是为了不漏生成自动备注
   */
  private Map expandEtcMap() {
    def etcKeys = _etcMap.values().stream()
        .flatMap { Map e -> e.keySet().stream() }
        .collect(Collectors.toSet()) as Set<String>

    def autoFill = { Map.Entry<String, Map> e ->
      Map attend = e.value
      return etcKeys.stream()
          .filter { attend.containsKey(it) }
          .collect(Collectors.toMap({ it }, { attend[it] }))
    }

    return _etcMap + _attendMap.entrySet().stream()
        .filter { !_etcMap.containsKey(it.key) }
        .collect(Collectors.toMap({ Map.Entry e -> e.key }, autoFill))
  }

  private Map processEtc(Map line) {
    GlobalResultMaker.Salary salary = _globalResult.salaryTime()
    LocalDate start = salary.start()
    LocalDate end = salary.end()
    def inRange = { LocalDate t -> t.isAfter(start.minusDays(1)) && t.isBefore(end.plusDays(1)) }

    String employeeId = line['工号']
    def getTime = { String col ->
      def basicLine = _basicMap[employeeId] as Map
      assert basicLine, "表[工资其他]存在无效数据：${employeeId}"

      Object time = basicLine[col]
      return (time instanceof LocalDateTime) ? time.toLocalDate() : null
    }

    def autoRemark = {
      def quitTime = getTime('离职时间')
      if (quitTime && inRange(quitTime)) {
        return '本月离职'
      }
      def regularTime = getTime('转正日期')
      if (regularTime && inRange(regularTime)) {
        return '本月转正'
      }
      def joinTime = getTime('入职日期')
      assert joinTime, line
      if (inRange(joinTime)) {
        return '本月入职'
      }
      return ''
    }

    def manualRemark = line['备注'] as String ?: ''
    return [
        '备注': [autoRemark(), manualRemark].join('\n').trim(),
    ]
  }

  /**
   * @see nina.yiyou.salary.input.info.AttendExcelV2Reader#COL
   */
  private Map processAttendance(Map line) {
    double attendActual = line['试用实际出勤'] + line['转正实际出勤']
    def hourToDay = { double h -> (h / 7.5).round(1) }

    def salary = new SalaryCalculator(line, _payMap).calc()
    return [
        '应出勤'  : hourToDay(line['应出勤'] as double),
        '实际出勤': hourToDay(attendActual),
        '全勤'    : (line['全勤'] == '是') ? 200 : 0,
        '工资总额': (salary.probationTotal() + salary.fullTotal()).round(2),
        '工资应发': (salary.probationActual() + salary.fullActual()).round(2),
    ]
  }

  /**
   * @see nina.yiyou.salary.input.info.InsuranceExcelV2Reader#makeColumnConfig
   */
  private Map processInsurance(Map line) {
    return [
        '社保总': -line['合计'],
        '养老险': -line['养老'],
        '失业险': -line['失业'],
        '医疗险': -line['医疗'],
    ]
  }

  /**
   * @see nina.yiyou.salary.input.info.FundExcelV2Reader#COLUMN_LIST
   */
  private Map processFund(Map line) {
    return [
        '公积金': -line['个人'],
    ]
  }

  private final Map _globalMap
  private final GlobalResultMaker.Result _globalResult

  private final Map _basicMap
  private final Map _etcMap

  private final Map _payMap
  private final Map _attendMap

  private final Map _insuranceMap
  private final Map _fundMap
}
